#
#include <unistd.h>
#include <sys/un.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <errno.h>
#include <string.h>

#include "pb.h"
#include "pb_decode.h"
#include "pb_encode.h"

#include "somb.h"
#include "somb_message.h"
#include "somb_manager.h"
#include "somb_common.h"
#include "somb_log.h"
#include "somb_sock.h"

bool sob_message_bytes_encode(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
    char *str = *arg;
    if (!pb_encode_tag_for_field(stream, field))
        return false;

    return pb_encode_string(stream, (uint8_t*)str, strlen(str));
}
bool sob_message_bytes_decode(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
    int i=0;
    char* tmp = *arg;
    while (stream->bytes_left)
    {
        uint64_t value;
        if (!pb_decode_varint(stream, &value))
            return false;
        *(tmp+i)=value;
        i++;
    }
    return true;
}

int32_t i32SOMB_Message_Decode(uint8_t *pBuffer,uint32_t BufferSize,void *pMsg,uint32_t MsgSize,const pb_msgdesc_t *fields)
{
    if(NULL == pMsg)
    {
        return SOMB_PARAM_ERR; 
    }

    if((0 == BufferSize)||(NULL == pBuffer))
    {
        memset(pMsg,0,sizeof(MsgSize));
        return SOMB_OK;
    }

    do{
        pb_istream_t istream = pb_istream_from_buffer(pBuffer,BufferSize);
        bool _decode_status_ = pb_decode(&istream, fields, pMsg);
        if(! _decode_status_ )
        {
            SOMB_LOG_ERR("decode failed,%s BufferSize=%d ",PB_GET_ERROR(&istream),BufferSize);
            //printf("decode failed,%s\n",PB_GET_ERROR(&istream));
            return SOMB_MSG_ENCODE_ERR;
        }
    }while(0);

    return SOMB_OK;
}
int32_t i32SOMB_Message_Encode(uint8_t*pBuffer,uint32_t *pBufferSize,void *pMsg,const pb_msgdesc_t *fields)
{
    do{
        if((NULL == pBuffer)||(NULL == pBufferSize)||(*pBufferSize == 0))
        {
            return SOMB_PARAM_ERR;
        }
        memset(pBuffer,0,*pBufferSize);
        pb_ostream_t ostream = pb_ostream_from_buffer(pBuffer,*pBufferSize);
        bool _encode_status_ = pb_encode(&ostream, fields, pMsg);
        if(! _encode_status_ )
        {
            SOMB_LOG_ERR("encode failed,%s BufferSize=%d",PB_GET_ERROR(&ostream),*pBufferSize);
            return SOMB_MSG_ENCODE_ERR;
        }
#if 1
        if(ostream.bytes_written)
        {
            *(pBufferSize) = ostream.bytes_written;
        }
        else
        {
            //*(pBufferSize)=0xFDFEFAFD;
            *(pBufferSize)=0;
            //printf("ostream.bytes_written=0\n");
        }
#else
        *(pBufferSize) = ostream.bytes_written;
#endif
        
    }while(0);

    return SOMB_OK;

}

int32_t i32SOMB_Msg_Send_2_Daemon(uint32_t MsgId, void *msgreq,const pb_msgdesc_t * reqfields,uint32_t reqfield_size)
{

    int32_t ret  = SOMB_FAIL;
    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    uint8_t *buffer=malloc(SOMB_DAEMON_MSG_HEADER_SIZE+reqfield_size);
    if(NULL == buffer)
    {
        SOMB_LOG_ERR("somb mng:(%s) pid(%d) malloc for msgreq msg(%d) failed",pstLocalSubNs->localexename,pstLocalSubNs->localpid,MsgId);
        return SOMB_FAIL;
    }
    memset(buffer,0,SOMB_DAEMON_MSG_HEADER_SIZE+reqfield_size);

    //SOMB_LOG_DEBUG("somb mng: reqfields=%p reqfield_size=%d",reqfields,reqfield_size);
    pb_ostream_t stream = pb_ostream_from_buffer(&(buffer[SOMB_DAEMON_MSG_HEADER_SIZE]), reqfield_size);
    bool status = pb_encode(&stream, reqfields, msgreq);
    if(!status)
    {
        SOMB_LOG_ERR("somb mng:pid(%d) sub ns id(%d) send MsgId(%d) to daemon, encode failed,%s",pstLocalSubNs->localpid,pstLocalSubNs->sub_ns_id,MsgId, PB_GET_ERROR(&stream));
        ret = SOMB_MSG_ENCODE_ERR;
        goto fail1;
    }

    *(uint32_t*)buffer = MsgId;
    *(uint32_t*)(buffer+4) = stream.bytes_written;
#if 0
    struct sockaddr_un un_addr;
    memset(&un_addr,0,sizeof(un_addr));

    un_addr.sun_family = AF_UNIX;
    snprintf(un_addr.sun_path,sizeof(un_addr.sun_path),"%s",SOMB_DAEMON_ADDR);
    //int32_t len = sendto(pstLocalSubNs->sk,buffer,SOMB_DAEMON_MSG_HEADER_SIZE+stream.bytes_written,0,(struct sockaddr *)&un_addr, SUN_LEN(&un_addr));
#endif
    int32_t len = send(pstLocalSubNs->sk,buffer,SOMB_DAEMON_MSG_HEADER_SIZE+stream.bytes_written,MSG_NOSIGNAL);
    if(len != SOMB_DAEMON_MSG_HEADER_SIZE+stream.bytes_written)
    {
        SOMB_LOG_ERR("somb mng:pid(%d) sub ns id(%d) send MsgId(%d) to daemon, len return failed,errno=%s",pstLocalSubNs->localpid,pstLocalSubNs->sub_ns_id,MsgId,strerror(errno));
        SOMB_LOG_ERR("somb mng:send msg len abnormal,len=%d (expected=%zu)",len,SOMB_DAEMON_MSG_HEADER_SIZE+stream.bytes_written);
        ret = SOMB_FAIL;
        goto fail1;
    }

    SOMB_LOG_DEBUG("somb mng:pid(%d) sub ns id(%d) send MsgId(%d) to daemon success,len=%d",pstLocalSubNs->localpid,pstLocalSubNs->sub_ns_id,MsgId,len);

    free(buffer);
    return SOMB_OK;
fail1:
    free(buffer);
    return ret;
}

